/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Simulation.Services.Main;

import Simulation.Config.Service.ServiceConfigReader;
import Simulation.Messages.*;
import Simulation.Services.Common.Hmi;
import Simulation.Services.Common.ServiceComms;
import Simulation.Services.Common.DisManager;
import Simulation.Services.Common.EntityDatabase;
import Simulation.Services.Common.Dis.EntityStatePdu;

/**
 *
 * @author aking2
 */
public class DynamicsService extends Service {
   
    ServiceConfigReader     config;
    float                   interServiceTimeoutSecs;
    Message                 interServiceMessage;    
    Hmi                     HmiService;
    HostConfigMessage       hostConfig = null;
    EntityDatabase          EntityDb;
    DisManager              Dis;

    @Override
    public void run() {
        StartService();

        while( true ) {
           
            // wait for next message
            interServiceMessage = comms.RecieveMessage(interServiceTimeoutSecs);
            
            switch( interServiceMessage.messageID ) {
                    
                case SYNC_PROCESS_INPUTS:
                    ProcessInputs();
                    break;                                        
                    
                case SYNC_SEND_OUTPUTS:
                    SendOutputs();
                    break;
                    
                case BEHV_HOST_CONFIG:
                    HandleMainConfiguration(interServiceMessage);                    
 
                case DIS_INCOMING_WRAPPED:
                    ProcessIncomingDisMessage(interServiceMessage);
                    break;
                    
                    
                default:
                    super.ProcessCommonMessage(interServiceMessage);
                    break;
            }            
            // Send Periodic Status Message
            super.SendStatusMessage();                 
        }
    }    
    
    public void ProcessIncomingDisMessage(Message m) {
        byte[] disMessage = new DisMessage(m).GetDisData();
        Dis.ProcessPduMessage(disMessage);        
    }
    
    public class UpdateEntityInEntityDatabase implements DisManager.Command
    {
        public void execute(Object data)
        {
            EntityDb.CreateRemoteEntity((EntityStatePdu)data);
        }
    }

    public class SendEntityStatePdu implements EntityDatabase.Command
    {
        public void execute(Object data)
        {
            Dis.BuildAndSendEntityStatePdu((EntityDatabase.EntityRecord)data);
        }
    }
    
    private void HandleMainConfiguration(Message m) {
        hostConfig = new HostConfigMessage(m);
        super.SetSimulationState(MessageCommonConstants.SIM_STATE_CONFUGURED);
    }
    
    public static void main(String args[]) {

        DynamicsService dynamicsService = new DynamicsService();
        dynamicsService.start(); 
    }      
   
    private void ProcessInputs() {        
                
        // Performance Monitoring
        super.ProcessInputsPerformanceStartOf();          
        
        // Performance Monitoring
        super.ProcessInputsPerformanceEndOf();
    }
    
    private void SendOutputs() {
                

        // Performance Monitoring
        super.SendOutputsPerformanceStartOf();
        
        
        /* 
         * Send Service Specific Data to other services* 
         */
        
        

        // Performance Monitoring
        super.SendOutputsPerformanceEndOf(); 
    }          
    
    
    private void StartService() {
        
        // Set what we are
        super.SetServiceId(MessageCommonConstants.DYNAMICS_SERVICE);
        super.SetSimularorId((byte)1);        
        
        System.out.println("Dynamics Service Loading Config");   
        config = new ServiceConfigReader("Simulation/Config/Service/DynamicsServiceConfig.txt");
        
        System.out.println("Dynamics Service Creating Read Socket");
        comms = new ServiceComms(
            config.GetData("INTER_SERVICE_READ_IP"),
            Integer.parseInt(config.GetData("INTER_SERVICE_READ_PORT"))
            );
        
        /*
         * Get IOS health message period
         */
        super.SetIosHealthSendPeriod((int) (
          (Float.parseFloat(config.GetData("IOS_HEALTH_SEND_PERIOD")) * 1000.0)));

        
        System.out.println("Dynamics Service Adding inter-service network destinations");   
        String datum1 = config.GetData("INTER_SERVICE_NUM_OF_NETWORK_DESTINATIONS");
        int num_of_inter_service_destiantions = Integer.parseInt(datum1);
        for( int i=0; i<num_of_inter_service_destiantions; i++) {
            comms.AddInterServiceDestiantion(
                config.GetData("INTER_SERVICE_NETWORK_DESTINATIONS_IP_" + String.valueOf(i+1)),
                Integer.parseInt(config.GetData("INTER_SERVICE_NETWORK_DESTINATIONS_PORT_" + String.valueOf(i+1))));
        }   
        
        System.out.println("Dynamics Service Adding IOS network destinations");   
        String datum2 = config.GetData("IOS_NUM_OF_NETWORK_DESTINATIONS");
        int num_of_ios_destiantions = Integer.parseInt(datum2);
        for( int i=0; i<num_of_ios_destiantions; i++) {
            comms.AddIosDestiantion(
                config.GetData("IOS_NETWORK_DESTINATIONS_IP_" + String.valueOf(i+1)),
                Integer.parseInt(config.GetData("IOS_NETWORK_DESTINATIONS_PORT_" + String.valueOf(i+1))));
        }           
        interServiceTimeoutSecs = Float.parseFloat(config.GetData("INTER_SERVICE_TIMEOUT_SECS"));          

       /*
        * Open Hmi connection either as a server or a client
        */
        HmiService = new Hmi();
        boolean OpenHmiConnection = (boolean) (Boolean.parseBoolean(config.GetData("HMI_OPEN_CONNECTION")));
        
        if (OpenHmiConnection){
            int Hmi_Unique_Id = (int) (Integer.parseInt(config.GetData("HMI_UNIQUE_ID")));
            String IPAddr = config.GetData("HMI_IP");
            String PortNum = config.GetData("HMI_PORT");
            boolean Create_Connection_As_Server = (boolean) Boolean.parseBoolean(config.GetData("HMI_IS_SERVER"));
            HmiService.EstablishConnection(Hmi_Unique_Id, IPAddr, PortNum, Create_Connection_As_Server);
        }

       /*
        * Create an entity database
        */
        EntityDb = new EntityDatabase();
        
        int maxEntDbSize = (int) (Integer.parseInt(config.GetData("ENTITY_DATABASE_MAX_SIZE")));
        int entTimeoutPeriod = (int) (Integer.parseInt(config.GetData("ENTITY_DATABASE_TIMEOUT_SEC")));
        
        //Update the max size and remote entity timeout threasholds
        EntityDb.UpdateDatabaseThreasholds(maxEntDbSize,entTimeoutPeriod);
        
        boolean EnableLocalEntityBroadcast = (boolean) (Boolean.parseBoolean(config.GetData("ENTITY_DATABASE_LOCAL_ENTITY_BROADCAST")));
        //If the flag is enabled allow the entity database to broadcast
        //all local entity states on the DIS network
        if (EnableLocalEntityBroadcast){
            EntityDb.EnablePduSend(new SendEntityStatePdu());
        }
        
       /*
        * Create a DIS manager
        */
        Dis = new DisManager();
        
        String disAddress = (String) (config.GetData("DIS_MANAGER_IP"));
        String disMCastGrp = (String) (config.GetData("DIS_MANAGER_MULTICAST_GROUP"));
        int disPort = (int) (Integer.parseInt(config.GetData("DIS_MANAGER_PORT")));
        int disSiteId = (int) (Integer.parseInt(config.GetData("DIS_MANAGER_SITE_ID")));
        int disAppId = (int) (Integer.parseInt(config.GetData("DIS_MANAGER_APPLICATION_ID")));
        
        //Setup the dis outgoing connection
        Dis.EstablishConnection(disAddress,disMCastGrp,disPort,disSiteId,disAppId);
        
        boolean EnableRemoteEntitylogging = (boolean) (Boolean.parseBoolean(config.GetData("DIS_MANAGER_REMOTE_ENTITY_LOGGING")));
        //If the flag is enabled allow the entity database to broadcast
        //all local entity states on the DIS network
        if (EnableRemoteEntitylogging){
            Dis.EnableRemoteEntityStoring(new UpdateEntityInEntityDatabase());
        }  

        super.SetMonitorPerformance( config.GetData("SETTINGS_MONITOR_PERFORMANCE").equalsIgnoreCase("True"));  
        
        System.out.println("Dynamics Service Running"); 
        super.SetSimulationState(MessageCommonConstants.SIM_STATE_UNCONFUGURED);
        super.SetHealthStatus(HealthMessage.STATUS_HEALTHY);        
    }
    
    private long lastTimeSentStatusMessage = 0;
    private int  iosHealthSendPeriod = 0;    
    
    
}
